1 /*
2 * Unity VSCode Support
3 *
4 * Seamless support for Microsoft Visual Studio Code in Unity
5 *
6 * Version:
7 * 2.7
8 *
9 * Authors:
10 * Matthew Davey <matthew.davey@dotbunny.com>
11 */
12 namespace dotBunny.Unity
13 {
14 using System;
15 using System.IO;
16 using System.Text.RegularExpressions;
17 using UnityEditor;
18 using UnityEngine;
19
20 [InitializeOnLoad]
21 public static class VSCode
22 {
23 /// <summary>
24 /// Current Version Number
25 /// </summary>
26 public const float Version = 2.7f;
27
28 /// <summary>
29 /// Current Version Code
30 /// </summary>
31 public const string VersionCode = "-RELEASE";
32
33 /// <summary>
34 /// Additional File Extensions
35 /// </summary>
36 public const string FileExtensions = ".ts, .bjs, .javascript, .json, .html";
37
38 /// <summary>
39 /// Download URL for Unity Debbuger
40 /// </summary>
41 public const string UnityDebuggerURL = "https://unity.gallery.vsassets.io/_apis/public/gallery/publisher/unity/extension/unity-debug/latest/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage";
42
43 #region Properties
44
45 /// <summary>
46 /// Path to VSCode executable
47 public static string CodePath
48 {
49 get
50 {
51 string current = EditorPrefs.GetString("VSCode_CodePath", "");
52 if(current == "" || !VSCodeExists(current))
53 {
54 //Value not set, set to "" or current path is invalid, try to autodetect it
55 //If autodetect fails, a error will be printed and the default value set
56 EditorPrefs.SetString("VSCode_CodePath", AutodetectCodePath());
57 //If its not installed or the install folder isn't a "normal" one,
58 //AutodetectCodePath will print a error message to the Unity Console
59 }
60 return EditorPrefs.GetString("VSCode_CodePath", current);
61 }
62 set
63 {
64 EditorPrefs.SetString("VSCode_CodePath", value);
65 }
66 }
67
68 /// <summary>
69 /// Get Program Files Path
70 /// </summary>
71 /// <returns>The platforms "Program Files" path.</returns>
72 static string ProgramFilesx86()
73 {
74 if( 8 == IntPtr.Size
75 || (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432"))))
76 {
77 return Environment.GetEnvironmentVariable("ProgramFiles(x86)");
78 }
79
80 return Environment.GetEnvironmentVariable("ProgramFiles");
81 }
82
83
84 /// <summary>
85 /// Should debug information be displayed in the Unity terminal?
86 /// </summary>
87 public static bool Debug
88 {
89 get
90 {
91 return EditorPrefs.GetBool("VSCode_Debug", false);
92 }
93 set
94 {
95 EditorPrefs.SetBool("VSCode_Debug", value);
96 }
97 }
98
99 /// <summary>
100 /// Is the Visual Studio Code Integration Enabled?
101 /// </summary>
102 /// <remarks>
103 /// We do not want to automatically turn it on, for in larger projects not everyone is using VSCode
104 /// </remarks>
105 public static bool Enabled
106 {
107 get
108 {
109 return EditorPrefs.GetBool("VSCode_Enabled", false);
110 }
111 set
112 {
113 // When turning the plugin on, we should remove all the previous project files
114 if (!Enabled && value)
115 {
116 ClearProjectFiles();
117 }
118 EditorPrefs.SetBool("VSCode_Enabled", value);
119 }
120 }
121 public static bool UseUnityDebugger
122 {
123 get
124 {
125 return EditorPrefs.GetBool("VSCode_UseUnityDebugger", false);
126 }
127 set
128 {
129 if ( value != UseUnityDebugger ) {
130
131 // Set value
132 EditorPrefs.SetBool("VSCode_UseUnityDebugger", value);
133
134 // Do not write the launch JSON file because the debugger uses its own
135 if ( value ) {
136 WriteLaunchFile = false;
137 }
138
139 // Update launch file
140 UpdateLaunchFile();
141 }
142 }
143 }
144
145 /// <summary>
146 /// When opening a project in Unity, should it automatically open in VS Code.
147 /// </summary>
148 public static bool AutoOpenEnabled
149 {
150 get
151 {
152 return EditorPrefs.GetBool("VSCode_AutoOpenEnabled", false);
153 }
154 set
155 {
156 EditorPrefs.SetBool("VSCode_AutoOpenEnabled", value);
157 }
158 }
159
160 /// <summary>
161 /// Should the launch.json file be written?
162 /// </summary>
163 /// <remarks>
164 /// Useful to disable if someone has their own custom one rigged up
165 /// </remarks>
166 public static bool WriteLaunchFile
167 {
168 get
169 {
170 return EditorPrefs.GetBool("VSCode_WriteLaunchFile", true);
171 }
172 set
173 {
174 EditorPrefs.SetBool("VSCode_WriteLaunchFile", value);
175 }
176 }
177
178 /// <summary>
179 /// Should the plugin automatically update itself.
180 /// </summary>
181 static bool AutomaticUpdates
182 {
183 get
184 {
185 return EditorPrefs.GetBool("VSCode_AutomaticUpdates", false);
186 }
187 set
188 {
189 EditorPrefs.SetBool("VSCode_AutomaticUpdates", value);
190 }
191 }
192
193 static float GitHubVersion
194 {
195 get
196 {
197 return EditorPrefs.GetFloat("VSCode_GitHubVersion", Version);
198 }
199 set
200 {
201 EditorPrefs.SetFloat("VSCode_GitHubVersion", value);
202 }
203 }
204
205 /// <summary>
206 /// When was the last time that the plugin was updated?
207 /// </summary>
208 static DateTime LastUpdate
209 {
210 get
211 {
212 // Feature creation date.
213 DateTime lastTime = new DateTime(2015, 10, 8);
214
215 if (EditorPrefs.HasKey("VSCode_LastUpdate"))
216 {
217 DateTime.TryParse(EditorPrefs.GetString("VSCode_LastUpdate"), out lastTime);
218 }
219 return lastTime;
220 }
221 set
222 {
223 EditorPrefs.SetString("VSCode_LastUpdate", value.ToString());
224 }
225 }
226
227 /// <summary>
228 /// Quick reference to the VSCode launch settings file
229 /// </summary>
230 static string LaunchPath
231 {
232 get
233 {
234 return SettingsFolder + System.IO.Path.DirectorySeparatorChar + "launch.json";
235 }
236 }
237
238 /// <summary>
239 /// The full path to the project
240 /// </summary>
241 static string ProjectPath
242 {
243 get
244 {
245 return System.IO.Path.GetDirectoryName(UnityEngine.Application.dataPath);
246 }
247 }
248
249 /// <summary>
250 /// Should the script editor be reverted when quiting Unity.
251 /// </summary>
252 /// <remarks>
253 /// Useful for environments where you do not use VSCode for everything.
254 /// </remarks>
255 static bool RevertExternalScriptEditorOnExit
256 {
257 get
258 {
259 return EditorPrefs.GetBool("VSCode_RevertScriptEditorOnExit", true);
260 }
261 set
262 {
263 EditorPrefs.SetBool("VSCode_RevertScriptEditorOnExit", value);
264 }
265 }
266
267 /// <summary>
268 /// Quick reference to the VSCode settings folder
269 /// </summary>
270 static string SettingsFolder
271 {
272 get
273 {
274 return ProjectPath + System.IO.Path.DirectorySeparatorChar + ".vscode";
275 }
276 }
277
278 static string SettingsPath
279 {
280
281 get
282 {
283 return SettingsFolder + System.IO.Path.DirectorySeparatorChar + "settings.json";
284 }
285 }
286
287 static int UpdateTime
288 {
289 get
290 {
291 return EditorPrefs.GetInt("VSCode_UpdateTime", 7);
292 }
293 set
294 {
295 EditorPrefs.SetInt("VSCode_UpdateTime", value);
296 }
297 }
298
299 #endregion
300
301 /// <summary>
302 /// Integration Constructor
303 /// </summary>
304 static VSCode()
305 {
306 if (Enabled)
307 {
308 UpdateUnityPreferences(true);
309 UpdateLaunchFile();
310
311 // Add Update Check
312 DateTime targetDate = LastUpdate.AddDays(UpdateTime);
313 if (DateTime.Now >= targetDate && AutomaticUpdates)
314 {
315 CheckForUpdate();
316 }
317
318 // Open VS Code automatically when project is loaded
319 if (AutoOpenEnabled)
320 {
321 CheckForAutoOpen();
322 }
323
324 }
325
326 // Event for when script is reloaded
327 System.AppDomain.CurrentDomain.DomainUnload += System_AppDomain_CurrentDomain_DomainUnload;
328 }
329 static void System_AppDomain_CurrentDomain_DomainUnload(object sender, System.EventArgs e)
330 {
331 if (Enabled && RevertExternalScriptEditorOnExit)
332 {
333 UpdateUnityPreferences(false);
334 }
335 }
336
337
338 #region Public Members
339
340 /// <summary>
341 /// Force Unity To Write Project File
342 /// </summary>
343 /// <remarks>
344 /// Reflection!
345 /// </remarks>
346 public static void SyncSolution()
347 {
348 System.Type T = System.Type.GetType("UnityEditor.SyncVS,UnityEditor");
349 System.Reflection.MethodInfo SyncSolution = T.GetMethod("SyncSolution", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
350 SyncSolution.Invoke(null, null);
351
352 }
353
354 /// <summary>
355 /// Update the solution files so that they work with VS Code
356 /// </summary>
357 public static void UpdateSolution()
358 {
359 // No need to process if we are not enabled
360 if (!VSCode.Enabled)
361 {
362 return;
363 }
364
365 if (VSCode.Debug)
366 {
367 UnityEngine.Debug.Log("[VSCode] Updating Solution & Project Files");
368 }
369
370 var currentDirectory = Directory.GetCurrentDirectory();
371 var solutionFiles = Directory.GetFiles(currentDirectory, "*.sln");
372 var projectFiles = Directory.GetFiles(currentDirectory, "*.csproj");
373
374 foreach (var filePath in solutionFiles)
375 {
376 string content = File.ReadAllText(filePath);
377 content = ScrubSolutionContent(content);
378
379 File.WriteAllText(filePath, content);
380
381 ScrubFile(filePath);
382 }
383
384 foreach (var filePath in projectFiles)
385 {
386 string content = File.ReadAllText(filePath);
387 content = ScrubProjectContent(content);
388
389 File.WriteAllText(filePath, content);
390
391 ScrubFile(filePath);
392 }
393
394 }
395
396 #endregion
397
398 #region Private Members
399
400 /// <summary>
401 /// Try to find automatically the installation of VSCode
402 /// </summary>
403 static string AutodetectCodePath()
404 {
405 string[] possiblePaths =
406 #if UNITY_EDITOR_OSX
407 {
408 "/Applications/Visual Studio Code.app",
409 "/Applications/Visual Studio Code - Insiders.app"
410 };
411 #elif UNITY_EDITOR_WIN
412 {
413 ProgramFilesx86() + Path.DirectorySeparatorChar + "Microsoft VS Code"
414 + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "code.cmd",
415 ProgramFilesx86() + Path.DirectorySeparatorChar + "Microsoft VS Code Insiders"
416 + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "code-insiders.cmd"
417 };
418 #else
419 {
420 "/usr/bin/code",
421 "/bin/code",
422 "/usr/local/bin/code"
423 };
424 #endif
425 for(int i = 0; i < possiblePaths.Length; i++)
426 {
427 if(VSCodeExists(possiblePaths[i]))
428 {
429 return possiblePaths[i];
430 }
431 }
432 PrintNotFound(possiblePaths[0]);
433 return possiblePaths[0]; //returns the default one, printing a warning message 'executable not found'
434 }
435
436 /// <summary>
437 /// Call VSCode with arguments
438 /// </summary>
439 static void CallVSCode(string args)
440 {
441 System.Diagnostics.Process proc = new System.Diagnostics.Process();
442 if(!VSCodeExists(CodePath))
443 {
444 PrintNotFound(CodePath);
445 return;
446 }
447
448 #if UNITY_EDITOR_OSX
449 proc.StartInfo.FileName = "open";
450
451 // Check the path to see if there is "Insiders"
452 if (CodePath.Contains("Insiders"))
453 {
454 proc.StartInfo.Arguments = " -n -b \"com.microsoft.VSCodeInsiders\" --args " + args.Replace(@"\", @"\\");
455 }
456 else
457 {
458 proc.StartInfo.Arguments = " -n -b \"com.microsoft.VSCode\" --args " + args.Replace(@"\", @"\\");
459 }
460
461 proc.StartInfo.UseShellExecute = false;
462 #elif UNITY_EDITOR_WIN
463 proc.StartInfo.FileName = CodePath;
464 proc.StartInfo.Arguments = args;
465 proc.StartInfo.UseShellExecute = false;
466 #else
467 proc.StartInfo.FileName = CodePath;
468 proc.StartInfo.Arguments = args.Replace(@"\", @"\\");
469 proc.StartInfo.UseShellExecute = false;
470 #endif
471 proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
472 proc.StartInfo.CreateNoWindow = true;
473 proc.StartInfo.RedirectStandardOutput = true;
474 proc.Start();
475 }
476
477 /// <summary>
478 /// Check for Updates with GitHub
479 /// </summary>
480 static void CheckForUpdate()
481 {
482 var fileContent = string.Empty;
483
484 EditorUtility.DisplayProgressBar("VSCode", "Checking for updates ...", 0.5f);
485
486 // Because were not a runtime framework, lets just use the simplest way of doing this
487 try
488 {
489 using (var webClient = new System.Net.WebClient())
490 {
491 fileContent = webClient.DownloadString("https://raw.githubusercontent.com/dotBunny/VSCode/master/Plugins/Editor/VSCode.cs");
492 }
493 }
494 catch (Exception e)
495 {
496 if (Debug)
497 {
498 UnityEngine.Debug.Log("[VSCode] " + e.Message);
499
500 }
501
502 // Don't go any further if there is an error
503 return;
504 }
505 finally
506 {
507 EditorUtility.ClearProgressBar();
508 }
509
510 // Set the last update time
511 LastUpdate = DateTime.Now;
512
513 // Fix for oddity in downlo
514 if (fileContent.Substring(0, 2) != "/*")
515 {
516 int startPosition = fileContent.IndexOf("/*", StringComparison.CurrentCultureIgnoreCase);
517
518 // Jump over junk characters
519 fileContent = fileContent.Substring(startPosition);
520 }
521
522 string[] fileExploded = fileContent.Split('\n');
523 if (fileExploded.Length > 7)
524 {
525 float github = Version;
526 if (float.TryParse(fileExploded[6].Replace("*", "").Trim(), out github))
527 {
528 GitHubVersion = github;
529 }
530
531
532 if (github > Version)
533 {
534 var GUIDs = AssetDatabase.FindAssets("t:Script VSCode");
535 var path = Application.dataPath.Substring(0, Application.dataPath.Length - "/Assets".Length) + System.IO.Path.DirectorySeparatorChar +
536 AssetDatabase.GUIDToAssetPath(GUIDs[0]).Replace('/', System.IO.Path.DirectorySeparatorChar);
537
538 if (EditorUtility.DisplayDialog("VSCode Update", "A newer version of the VSCode plugin is available, would you like to update your version?", "Yes", "No"))
539 {
540 // Always make sure the file is writable
541 System.IO.FileInfo fileInfo = new System.IO.FileInfo(path);
542 fileInfo.IsReadOnly = false;
543
544 // Write update file
545 File.WriteAllText(path, fileContent);
546
547 // Force update on text file
548 AssetDatabase.ImportAsset(AssetDatabase.GUIDToAssetPath(GUIDs[0]), ImportAssetOptions.ForceUpdate);
549 }
550
551 }
552 }
553 }
554
555 /// <summary>
556 /// Checks whether it should auto-open VSCode
557 /// </summary>
558 /// <remarks>
559 /// VSCode() gets called on Launch and Run, through IntializeOnLoad
560 /// https://docs.unity3d.com/ScriptReference/InitializeOnLoadAttribute.html
561 /// To make sure it only opens VSCode when Unity (re)launches (i.e. opens a project),
562 /// we compare the launch time, which we calculate using EditorApplication.timeSinceStartup.
563 /// </remarks>
564 static void CheckForAutoOpen()
565 {
566 double timeInSeconds = (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
567 int unityLaunchTimeInSeconds = (int)(timeInSeconds - EditorApplication.timeSinceStartup);
568 int prevUnityLaunchTime = EditorPrefs.GetInt("VSCode_UnityLaunchTime", 0);
569 // If launch time has changed, then Unity was re-opened
570 if (unityLaunchTimeInSeconds > prevUnityLaunchTime) {
571 // Launch VSCode
572 VSCode.MenuOpenProject();
573 // Save new launch time
574 EditorPrefs.SetInt("VSCode_UnityLaunchTime", unityLaunchTimeInSeconds);
575 }
576 }
577
578 /// <summary>
579 /// Clear out any existing project files and lingering stuff that might cause problems
580 /// </summary>
581 static void ClearProjectFiles()
582 {
583 var currentDirectory = Directory.GetCurrentDirectory();
584 var solutionFiles = Directory.GetFiles(currentDirectory, "*.sln");
585 var projectFiles = Directory.GetFiles(currentDirectory, "*.csproj");
586 var unityProjectFiles = Directory.GetFiles(currentDirectory, "*.unityproj");
587
588 foreach (string solutionFile in solutionFiles)
589 {
590 File.Delete(solutionFile);
591 }
592 foreach (string projectFile in projectFiles)
593 {
594 File.Delete(projectFile);
595 }
596 foreach (string unityProjectFile in unityProjectFiles)
597 {
598 File.Delete(unityProjectFile);
599 }
600
601 // Replace with our clean files (only in Unity 5)
602 #if !UNITY_4_0 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 && !UNITY_4_6 && !UNITY_4_7
603 SyncSolution();
604 #endif
605 }
606
607 /// <summary>
608 /// Force Unity Preferences Window To Read From Settings
609 /// </summary>
610 static void FixUnityPreferences()
611 {
612 // I want that window, please and thank you
613 System.Type T = System.Type.GetType("UnityEditor.PreferencesWindow,UnityEditor");
614
615 if (EditorWindow.focusedWindow == null)
616 return;
617
618 // Only run this when the editor window is visible (cause its what screwed us up)
619 if (EditorWindow.focusedWindow.GetType() == T)
620 {
621 var window = EditorWindow.GetWindow(T, true, "Unity Preferences");
622
623
624 if (window == null)
625 {
626 if (Debug)
627 {
628 UnityEngine.Debug.Log("[VSCode] No Preferences Window Found (really?)");
629 }
630 return;
631 }
632
633 var invokerType = window.GetType();
634 var invokerMethod = invokerType.GetMethod("ReadPreferences",
635 System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
636
637 if (invokerMethod != null)
638 {
639 invokerMethod.Invoke(window, null);
640 }
641 else if (Debug)
642 {
643 UnityEngine.Debug.Log("[VSCode] No Reflection Method Found For Preferences");
644 }
645 }
646 }
647
648 /// <summary>
649 /// Determine what port Unity is listening for on Windows
650 /// </summary>
651 static int GetDebugPort()
652 {
653 #if UNITY_EDITOR_WIN
654 System.Diagnostics.Process process = new System.Diagnostics.Process();
655 process.StartInfo.FileName = "netstat";
656 process.StartInfo.Arguments = "-a -n -o -p TCP";
657 process.StartInfo.UseShellExecute = false;
658 process.StartInfo.RedirectStandardOutput = true;
659 process.Start();
660
661 string output = process.StandardOutput.ReadToEnd();
662 string[] lines = output.Split('\n');
663
664 process.WaitForExit();
665
666 foreach (string line in lines)
667 {
668 string[] tokens = Regex.Split(line, "\\s+");
669 if (tokens.Length > 4)
670 {
671 int test = -1;
672 int.TryParse(tokens[5], out test);
673
674 if (test > 1023)
675 {
676 try
677 {
678 var p = System.Diagnostics.Process.GetProcessById(test);
679 if (p.ProcessName == "Unity")
680 {
681 return test;
682 }
683 }
684 catch
685 {
686
687 }
688 }
689 }
690 }
691 #else
692 System.Diagnostics.Process process = new System.Diagnostics.Process();
693 process.StartInfo.FileName = "lsof";
694 process.StartInfo.Arguments = "-c /^Unity$/ -i 4tcp -a";
695 process.StartInfo.UseShellExecute = false;
696 process.StartInfo.RedirectStandardOutput = true;
697 process.Start();
698
699 // Not thread safe (yet!)
700 string output = process.StandardOutput.ReadToEnd();
701 string[] lines = output.Split('\n');
702
703 process.WaitForExit();
704
705 foreach (string line in lines)
706 {
707 int port = -1;
708 if (line.StartsWith("Unity"))
709 {
710 string[] portions = line.Split(new string[] { "TCP *:" }, System.StringSplitOptions.None);
711 if (portions.Length >= 2)
712 {
713 Regex digitsOnly = new Regex(@"[^\d]");
714 string cleanPort = digitsOnly.Replace(portions[1], "");
715 if (int.TryParse(cleanPort, out port))
716 {
717 if (port > -1)
718 {
719 return port;
720 }
721 }
722 }
723 }
724 }
725 #endif
726 return -1;
727 }
728
729 /// <summary>
730 /// Manually install the original Unity Debuger
731 /// </summary>
732 /// <remarks>
733 /// This should auto update to the latest.
734 /// </remarks>
735 static void InstallUnityDebugger()
736 {
737 EditorUtility.DisplayProgressBar("VSCode", "Downloading Unity Debugger ...", 0.1f);
738 byte[] fileContent;
739
740 try
741 {
742 using (var webClient = new System.Net.WebClient())
743 {
744 fileContent = webClient.DownloadData(UnityDebuggerURL);
745 }
746 }
747 catch (Exception e)
748 {
749 if (Debug)
750 {
751 UnityEngine.Debug.Log("[VSCode] " + e.Message);
752 }
753 // Don't go any further if there is an error
754 return;
755 }
756 finally
757 {
758 EditorUtility.ClearProgressBar();
759 }
760
761 // Do we have a file to install?
762 if ( fileContent != null ) {
763 string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".vsix";
764 File.WriteAllBytes(fileName, fileContent);
765
766 CallVSCode(fileName);
767 }
768
769 }
770
771 // HACK: This is in until Unity can figure out why MD keeps opening even though a different program is selected.
772 [MenuItem("Assets/Open C# Project In Code", false, 1000)]
773 static void MenuOpenProject()
774 {
775 // Force the project files to be sync
776 SyncSolution();
777
778 // Load Project
779 CallVSCode("\"" + ProjectPath + "\"");
780 }
781
782 /// <summary>
783 /// Print a error message to the Unity Console about not finding the code executable
784 /// </summary>
785 static void PrintNotFound(string path)
786 {
787 UnityEngine.Debug.LogError("[VSCode] Code executable in '" + path + "' not found. Check your" +
788 "Visual Studio Code installation and insert the correct path in the Preferences menu.");
789 }
790
791 [MenuItem("Assets/Open C# Project In Code", true, 1000)]
792 static bool ValidateMenuOpenProject()
793 {
794 return Enabled;
795 }
796
797 /// <summary>
798 /// VS Code Integration Preferences Item
799 /// </summary>
800 /// <remarks>
801 /// Contains all 3 toggles: Enable/Disable; Debug On/Off; Writing Launch File On/Off
802 /// </remarks>
803 [PreferenceItem("VSCode")]
804 static void VSCodePreferencesItem()
805 {
806 if (EditorApplication.isCompiling)
807 {
808 EditorGUILayout.HelpBox("Please wait for Unity to finish compiling. \nIf the window doesn't refresh, simply click on the window or move it around to cause a repaint to happen.", MessageType.Warning);
809 return;
810 }
811 EditorGUILayout.BeginVertical();
812
813 var developmentInfo = "Support development of this plugin, follow @reapazor and @dotbunny on Twitter.";
814 var versionInfo = string.Format("{0:0.00}", Version) + VersionCode + ", GitHub version @ " + string.Format("{0:0.00}", GitHubVersion);
815 EditorGUILayout.HelpBox(developmentInfo + " --- [ " + versionInfo + " ]", MessageType.None);
816
817 EditorGUI.BeginChangeCheck();
818
819 // Need the VS Code executable
820 EditorGUILayout.BeginHorizontal();
821 EditorGUILayout.LabelField("VS Code Path", GUILayout.Width(75));
822 #if UNITY_5_3_OR_NEWER
823 CodePath = EditorGUILayout.DelayedTextField(CodePath, GUILayout.ExpandWidth(true));
824 #else
825 CodePath = EditorGUILayout.TextField(CodePath, GUILayout.ExpandWidth(true));
826 #endif
827 GUI.SetNextControlName("PathSetButton");
828 if(GUILayout.Button("...", GUILayout.Height(14), GUILayout.Width(20)))
829 {
830 GUI.FocusControl("PathSetButton");
831 string path = EditorUtility.OpenFilePanel( "Visual Studio Code Executable", "", "" );
832 if( path.Length != 0 && File.Exists(path) || Directory.Exists(path))
833 {
834 CodePath = path;
835 }
836 }
837 EditorGUILayout.EndHorizontal();
838 EditorGUILayout.Space();
839
840 Enabled = EditorGUILayout.Toggle(new GUIContent("Enable Integration", "Should the integration work its magic for you?"), Enabled);
841
842 UseUnityDebugger = EditorGUILayout.Toggle(new GUIContent("Use Unity Debugger", "Should the integration integrate with Unity's VSCode Extension (must be installed)."), UseUnityDebugger);
843
844 AutoOpenEnabled = EditorGUILayout.Toggle(new GUIContent("Enable Auto Open", "When opening a project in Unity, should it automatically open in VS Code?"), AutoOpenEnabled);
845
846 EditorGUILayout.Space();
847 RevertExternalScriptEditorOnExit = EditorGUILayout.Toggle(new GUIContent("Revert Script Editor On Unload", "Should the external script editor setting be reverted to its previous setting on project unload? This is useful if you do not use Code with all your projects."),RevertExternalScriptEditorOnExit);
848
849 Debug = EditorGUILayout.Toggle(new GUIContent("Output Messages To Console", "Should informational messages be sent to Unity's Console?"), Debug);
850
851 WriteLaunchFile = EditorGUILayout.Toggle(new GUIContent("Always Write Launch File", "Always write the launch.json settings when entering play mode?"), WriteLaunchFile);
852
853 EditorGUILayout.Space();
854
855 AutomaticUpdates = EditorGUILayout.Toggle(new GUIContent("Automatic Updates", "Should the plugin automatically update itself?"), AutomaticUpdates);
856
857 UpdateTime = EditorGUILayout.IntSlider(new GUIContent("Update Timer (Days)", "After how many days should updates be checked for?"), UpdateTime, 1, 31);
858
859 EditorGUILayout.Space();
860 EditorGUILayout.Space();
861
862 if (EditorGUI.EndChangeCheck())
863 {
864 UpdateUnityPreferences(Enabled);
865
866 // TODO: Force Unity To Reload Preferences
867 // This seems to be a hick up / issue
868 if (VSCode.Debug)
869 {
870 if (Enabled)
871 {
872 UnityEngine.Debug.Log("[VSCode] Integration Enabled");
873 }
874 else
875 {
876 UnityEngine.Debug.Log("[VSCode] Integration Disabled");
877 }
878 }
879 }
880
881 if (GUILayout.Button(new GUIContent("Force Update", "Check for updates to the plugin, right NOW!")))
882 {
883 CheckForUpdate();
884 EditorGUILayout.EndVertical();
885 return;
886 }
887 if (GUILayout.Button(new GUIContent("Write Workspace Settings", "Output a default set of workspace settings for VSCode to use, ignoring many different types of files.")))
888 {
889 WriteWorkspaceSettings();
890 EditorGUILayout.EndVertical();
891 return;
892 }
893 EditorGUILayout.Space();
894
895 if (UseUnityDebugger)
896 {
897 EditorGUILayout.HelpBox("In order for the \"Use Unity Debuggger\" option to function above, you need to have installed the Unity Debugger Extension for Visual Studio Code.", MessageType.Warning);
898 if (GUILayout.Button(new GUIContent("Install Unity Debugger", "Install the Unity Debugger Extension into Code")))
899 {
900 InstallUnityDebugger();
901 EditorGUILayout.EndVertical();
902 return;
903 }
904 }
905
906 }
907
908 /// <summary>
909 /// Asset Open Callback (from Unity)
910 /// </summary>
911 /// <remarks>
912 /// Called when Unity is about to open an asset.
913 /// </remarks>
914 [UnityEditor.Callbacks.OnOpenAssetAttribute()]
915 static bool OnOpenedAsset(int instanceID, int line)
916 {
917 // bail out if we are not using VSCode
918 if (!Enabled)
919 {
920 return false;
921 }
922
923 // current path without the asset folder
924 string appPath = ProjectPath;
925
926 // determine asset that has been double clicked in the project view
927 UnityEngine.Object selected = EditorUtility.InstanceIDToObject(instanceID);
928
929 // additional file extensions
930 string selectedFilePath = AssetDatabase.GetAssetPath(selected);
931 string selectedFileExt = Path.GetExtension(selectedFilePath);
932 if (selectedFileExt == null) {
933 selectedFileExt = String.Empty;
934 }
935 if (!String.IsNullOrEmpty(selectedFileExt)) {
936 selectedFileExt = selectedFileExt.ToLower();
937 }
938
939 // open supported object types
940 if (selected.GetType().ToString() == "UnityEditor.MonoScript" ||
941 selected.GetType().ToString() == "UnityEngine.Shader" ||
942 VSCode.FileExtensions.IndexOf(selectedFileExt, StringComparison.OrdinalIgnoreCase) >= 0)
943 {
944 string completeFilepath = appPath + Path.DirectorySeparatorChar + AssetDatabase.GetAssetPath(selected);
945
946 string args = null;
947 if (line == -1)
948 {
949 args = "\"" + ProjectPath + "\" \"" + completeFilepath + "\" -r";
950 }
951 else
952 {
953 args = "\"" + ProjectPath + "\" -g \"" + completeFilepath + ":" + line.ToString() + "\" -r";
954 }
955 // call 'open'
956 CallVSCode(args);
957
958 return true;
959 }
960
961 // Didnt find a code file? let Unity figure it out
962 return false;
963
964 }
965
966 /// <summary>
967 /// Executed when the Editor's playmode changes allowing for capture of required data
968 /// </summary>
969 static void OnPlaymodeStateChanged()
970 {
971 if (UnityEngine.Application.isPlaying && EditorApplication.isPlayingOrWillChangePlaymode)
972 {
973 UpdateLaunchFile();
974 }
975 }
976
977 /// <summary>
978 /// Detect when scripts are reloaded and relink playmode detection
979 /// </summary>
980 [UnityEditor.Callbacks.DidReloadScripts()]
981 static void OnScriptReload()
982 {
983 EditorApplication.playmodeStateChanged -= OnPlaymodeStateChanged;
984 EditorApplication.playmodeStateChanged += OnPlaymodeStateChanged;
985 }
986
987 /// <summary>
988 /// Remove extra/erroneous lines from a file.
989 static void ScrubFile(string path)
990 {
991 string[] lines = File.ReadAllLines(path);
992 System.Collections.Generic.List<string> newLines = new System.Collections.Generic.List<string>();
993 for (int i = 0; i < lines.Length; i++)
994 {
995 // Check Empty
996 if (string.IsNullOrEmpty(lines[i].Trim()) || lines[i].Trim() == "\t" || lines[i].Trim() == "\t\t")
997 {
998
999 }
1000 else
1001 {
1002 newLines.Add(lines[i]);
1003 }
1004 }
1005 File.WriteAllLines(path, newLines.ToArray());
1006 }
1007
1008 /// <summary>
1009 /// Remove extra/erroneous data from project file (content).
1010 /// </summary>
1011 static string ScrubProjectContent(string content)
1012 {
1013 if (content.Length == 0)
1014 return "";
1015
1016 #if !UNITY_EDITOR_WIN
1017 // Moved to 3.5, 2.0 is legacy.
1018 if (content.IndexOf("<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>") != -1)
1019 {
1020 content = Regex.Replace(content, "<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>", "<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>");
1021 }
1022 #endif
1023
1024 string targetPath = "";// "<TargetPath>Temp" + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "Debug" + Path.DirectorySeparatorChar + "</TargetPath>"; //OutputPath
1025 string langVersion = "<LangVersion>default</LangVersion>";
1026
1027
1028 bool found = true;
1029 int location = 0;
1030 string addedOptions = "";
1031 int startLocation = -1;
1032 int endLocation = -1;
1033 int endLength = 0;
1034
1035 while (found)
1036 {
1037 startLocation = -1;
1038 endLocation = -1;
1039 endLength = 0;
1040 addedOptions = "";
1041 startLocation = content.IndexOf("<PropertyGroup", location);
1042
1043 if (startLocation != -1)
1044 {
1045
1046 endLocation = content.IndexOf("</PropertyGroup>", startLocation);
1047 endLength = (endLocation - startLocation);
1048
1049
1050 if (endLocation == -1)
1051 {
1052 found = false;
1053 continue;
1054 }
1055 else
1056 {
1057 found = true;
1058 location = endLocation;
1059 }
1060
1061 if (content.Substring(startLocation, endLength).IndexOf("<TargetPath>") == -1)
1062 {
1063 addedOptions += "\n\r\t" + targetPath + "\n\r";
1064 }
1065
1066 if (content.Substring(startLocation, endLength).IndexOf("<LangVersion>") == -1)
1067 {
1068 addedOptions += "\n\r\t" + langVersion + "\n\r";
1069 }
1070
1071 if (!string.IsNullOrEmpty(addedOptions))
1072 {
1073 content = content.Substring(0, endLocation) + addedOptions + content.Substring(endLocation);
1074 }
1075 }
1076 else
1077 {
1078 found = false;
1079 }
1080 }
1081
1082 return content;
1083 }
1084
1085 /// <summary>
1086 /// Remove extra/erroneous data from solution file (content).
1087 /// </summary>
1088 static string ScrubSolutionContent(string content)
1089 {
1090 // Replace Solution Version
1091 content = content.Replace(
1092 "Microsoft Visual Studio Solution File, Format Version 11.00\r\n# Visual Studio 2008\r\n",
1093 "\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio 2012");
1094
1095 // Remove Solution Properties (Unity Junk)
1096 int startIndex = content.IndexOf("GlobalSection(SolutionProperties) = preSolution");
1097 if (startIndex != -1)
1098 {
1099 int endIndex = content.IndexOf("EndGlobalSection", startIndex);
1100 content = content.Substring(0, startIndex) + content.Substring(endIndex + 16);
1101 }
1102
1103 return content;
1104 }
1105
1106 /// <summary>
1107 /// Update Visual Studio Code Launch file
1108 /// </summary>
1109 static void UpdateLaunchFile()
1110 {
1111 if (!VSCode.Enabled)
1112 {
1113 return;
1114 }
1115 else if (VSCode.UseUnityDebugger)
1116 {
1117 if (!Directory.Exists(VSCode.SettingsFolder))
1118 System.IO.Directory.CreateDirectory(VSCode.SettingsFolder);
1119
1120 // Write out proper formatted JSON (hence no more SimpleJSON here)
1121 string fileContent = "{\n\t\"version\": \"0.2.0\",\n\t\"configurations\": [\n\t\t{\n\t\t\t\"name\": \"Unity Editor\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"Windows Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"OSX Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"Linux Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"iOS Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\t\t},\n\t\t{\n\t\t\t\"name\": \"Android Player\",\n\t\t\t\"type\": \"unity\",\n\t\t\t\"request\": \"launch\"\n\n\t\t}\n\t]\n}";
1122 File.WriteAllText(VSCode.LaunchPath, fileContent);
1123 }
1124 else if (VSCode.WriteLaunchFile)
1125 {
1126 int port = GetDebugPort();
1127 if (port > -1)
1128 {
1129 if (!Directory.Exists(VSCode.SettingsFolder))
1130 System.IO.Directory.CreateDirectory(VSCode.SettingsFolder);
1131
1132 // Write out proper formatted JSON (hence no more SimpleJSON here)
1133 string fileContent = "{\n\t\"version\":\"0.2.0\",\n\t\"configurations\":[ \n\t\t{\n\t\t\t\"name\":\"Unity\",\n\t\t\t\"type\":\"mono\",\n\t\t\t\"request\":\"attach\",\n\t\t\t\"address\":\"localhost\",\n\t\t\t\"port\":" + port + "\n\t\t}\n\t]\n}";
1134 File.WriteAllText(VSCode.LaunchPath, fileContent);
1135
1136 if (VSCode.Debug)
1137 {
1138 UnityEngine.Debug.Log("[VSCode] Debug Port Found (" + port + ")");
1139 }
1140 }
1141 else
1142 {
1143 if (VSCode.Debug)
1144 {
1145 UnityEngine.Debug.LogWarning("[VSCode] Unable to determine debug port.");
1146 }
1147 }
1148 }
1149 }
1150
1151 /// <summary>
1152 /// Update Unity Editor Preferences
1153 /// </summary>
1154 /// <param name="enabled">Should we turn on this party!</param>
1155 static void UpdateUnityPreferences(bool enabled)
1156 {
1157 if (enabled)
1158 {
1159 // App
1160 if (EditorPrefs.GetString("kScriptsDefaultApp") != CodePath)
1161 {
1162 EditorPrefs.SetString("VSCode_PreviousApp", EditorPrefs.GetString("kScriptsDefaultApp"));
1163 }
1164 EditorPrefs.SetString("kScriptsDefaultApp", CodePath);
1165
1166 // Arguments
1167 if (EditorPrefs.GetString("kScriptEditorArgs") != "-r -g `$(File):$(Line)`")
1168 {
1169 EditorPrefs.SetString("VSCode_PreviousArgs", EditorPrefs.GetString("kScriptEditorArgs"));
1170 }
1171
1172 EditorPrefs.SetString("kScriptEditorArgs", "-r -g `$(File):$(Line)`");
1173 EditorPrefs.SetString("kScriptEditorArgs" + CodePath, "-r -g `$(File):$(Line)`");
1174
1175
1176 // MonoDevelop Solution
1177 if (EditorPrefs.GetBool("kMonoDevelopSolutionProperties", false))
1178 {
1179 EditorPrefs.SetBool("VSCode_PreviousMD", true);
1180 }
1181 EditorPrefs.SetBool("kMonoDevelopSolutionProperties", false);
1182
1183 // Support Unity Proj (JS)
1184 if (EditorPrefs.GetBool("kExternalEditorSupportsUnityProj", false))
1185 {
1186 EditorPrefs.SetBool("VSCode_PreviousUnityProj", true);
1187 }
1188 EditorPrefs.SetBool("kExternalEditorSupportsUnityProj", false);
1189
1190 if (!EditorPrefs.GetBool("AllowAttachedDebuggingOfEditor", false))
1191 {
1192 EditorPrefs.SetBool("VSCode_PreviousAttach", false);
1193 }
1194 EditorPrefs.SetBool("AllowAttachedDebuggingOfEditor", true);
1195
1196 }
1197 else
1198 {
1199 // Restore previous app
1200 if (!string.IsNullOrEmpty(EditorPrefs.GetString("VSCode_PreviousApp")))
1201 {
1202 EditorPrefs.SetString("kScriptsDefaultApp", EditorPrefs.GetString("VSCode_PreviousApp"));
1203 }
1204
1205 // Restore previous args
1206 if (!string.IsNullOrEmpty(EditorPrefs.GetString("VSCode_PreviousArgs")))
1207 {
1208 EditorPrefs.SetString("kScriptEditorArgs", EditorPrefs.GetString("VSCode_PreviousArgs"));
1209 }
1210
1211 // Restore MD setting
1212 if (EditorPrefs.GetBool("VSCode_PreviousMD", false))
1213 {
1214 EditorPrefs.SetBool("kMonoDevelopSolutionProperties", true);
1215 }
1216
1217 // Restore MD setting
1218 if (EditorPrefs.GetBool("VSCode_PreviousUnityProj", false))
1219 {
1220 EditorPrefs.SetBool("kExternalEditorSupportsUnityProj", true);
1221 }
1222
1223 // Always leave editor attaching on, I know, it solves the problem of needing to restart for this
1224 // to actually work
1225 EditorPrefs.SetBool("AllowAttachedDebuggingOfEditor", true);
1226
1227 }
1228
1229 FixUnityPreferences();
1230 }
1231
1232 /// <summary>
1233 /// Determines if the current path to the code executable is valid or not (exists)
1234 /// </summary>
1235 static bool VSCodeExists(string curPath)
1236 {
1237 #if UNITY_EDITOR_OSX
1238 return System.IO.Directory.Exists(curPath);
1239 #else
1240 System.IO.FileInfo code = new System.IO.FileInfo(curPath);
1241 return code.Exists;
1242 #endif
1243 }
1244
1245 /// <summary>
1246 /// Write Default Workspace Settings
1247 /// </summary>
1248 static void WriteWorkspaceSettings()
1249 {
1250 if (Debug)
1251 {
1252 UnityEngine.Debug.Log("[VSCode] Workspace Settings Written");
1253 }
1254
1255 if (!Directory.Exists(VSCode.SettingsFolder))
1256 {
1257 System.IO.Directory.CreateDirectory(VSCode.SettingsFolder);
1258 }
1259
1260 string exclusions =
1261 // Associations
1262 "{\n" +
1263 "\t\"files.associations\":\n" +
1264 "\t{\n" +
1265 "\t\t\"*.bjs\":\"javascript\",\n" +
1266 "\t\t\"*.javascript\":\"javascript\"\n" +
1267 "\t},\n" +
1268 "\t\"files.exclude\":\n" +
1269 "\t{\n" +
1270 // Hidden Files
1271 "\t\t\"**/.DS_Store\":true,\n" +
1272 "\t\t\"**/.git\":true,\n" +
1273 "\t\t\"**/.gitignore\":true,\n" +
1274 "\t\t\"**/.gitattributes\":true,\n" +
1275 "\t\t\"**/.gitmodules\":true,\n" +
1276 "\t\t\"**/.svn\":true,\n" +
1277
1278
1279 // Project Files
1280 "\t\t\"**/*.booproj\":true,\n" +
1281 "\t\t\"**/*.pidb\":true,\n" +
1282 "\t\t\"**/*.suo\":true,\n" +
1283 "\t\t\"**/*.user\":true,\n" +
1284 "\t\t\"**/*.userprefs\":true,\n" +
1285 "\t\t\"**/*.unityproj\":true,\n" +
1286 "\t\t\"**/*.dll\":true,\n" +
1287 "\t\t\"**/*.exe\":true,\n" +
1288
1289 // Media Files
1290 "\t\t\"**/*.pdf\":true,\n" +
1291
1292 // Video
1293 "\t\t\"**/*.mp4\":true,\n" +
1294
1295 // Audio
1296 "\t\t\"**/*.mid\":true,\n" +
1297 "\t\t\"**/*.midi\":true,\n" +
1298 "\t\t\"**/*.wav\":true,\n" +
1299 "\t\t\"**/*.mp3\":true,\n" +
1300 "\t\t\"**/*.ogg\":true,\n" +
1301
1302 // Textures
1303 "\t\t\"**/*.gif\":true,\n" +
1304 "\t\t\"**/*.ico\":true,\n" +
1305 "\t\t\"**/*.jpg\":true,\n" +
1306 "\t\t\"**/*.jpeg\":true,\n" +
1307 "\t\t\"**/*.png\":true,\n" +
1308 "\t\t\"**/*.psd\":true,\n" +
1309 "\t\t\"**/*.tga\":true,\n" +
1310 "\t\t\"**/*.tif\":true,\n" +
1311 "\t\t\"**/*.tiff\":true,\n" +
1312 "\t\t\"**/*.hdr\":true,\n" +
1313 "\t\t\"**/*.exr\":true,\n" +
1314
1315 // Models
1316 "\t\t\"**/*.3ds\":true,\n" +
1317 "\t\t\"**/*.3DS\":true,\n" +
1318 "\t\t\"**/*.fbx\":true,\n" +
1319 "\t\t\"**/*.FBX\":true,\n" +
1320 "\t\t\"**/*.lxo\":true,\n" +
1321 "\t\t\"**/*.LXO\":true,\n" +
1322 "\t\t\"**/*.ma\":true,\n" +
1323 "\t\t\"**/*.MA\":true,\n" +
1324 "\t\t\"**/*.obj\":true,\n" +
1325 "\t\t\"**/*.OBJ\":true,\n" +
1326
1327 // Unity File Types
1328 "\t\t\"**/*.asset\":true,\n" +
1329 "\t\t\"**/*.cubemap\":true,\n" +
1330 "\t\t\"**/*.flare\":true,\n" +
1331 "\t\t\"**/*.mat\":true,\n" +
1332 "\t\t\"**/*.meta\":true,\n" +
1333 "\t\t\"**/*.prefab\":true,\n" +
1334 "\t\t\"**/*.unity\":true,\n" +
1335
1336 // Folders
1337 "\t\t\"build/\":true,\n" +
1338 "\t\t\"Build/\":true,\n" +
1339 "\t\t\"Library/\":true,\n" +
1340 "\t\t\"library/\":true,\n" +
1341 "\t\t\"obj/\":true,\n" +
1342 "\t\t\"Obj/\":true,\n" +
1343 "\t\t\"ProjectSettings/\":true,\r" +
1344 "\t\t\"temp/\":true,\n" +
1345 "\t\t\"Temp/\":true\n" +
1346 "\t}\n" +
1347 "}";
1348
1349 // Dont like the replace but it fixes the issue with the JSON
1350 File.WriteAllText(VSCode.SettingsPath, exclusions);
1351 }
1352
1353 #endregion
1354 }
1355
1356 /// <summary>
1357 /// VSCode Asset AssetPostprocessor
1358 /// <para>This will ensure any time that the project files are generated the VSCode versions will be made</para>
1359 /// </summary>
1360 /// <remarks>Undocumented Event</remarks>
1361 public class VSCodeAssetPostprocessor : AssetPostprocessor
1362 {
1363 /// <summary>
1364 /// On documented, project generation event callback
1365 /// </summary>
1366 private static void OnGeneratedCSProjectFiles()
1367 {
1368 // Force execution of VSCode update
1369 VSCode.UpdateSolution();
1370 }
1371 }
1372 }
Current Version Number
Current Version Code
Additional File Extensions
Download URL for Unity Debbuger
public const string UnityDebuggerURL = "https:unity.gallery.vsassets.io_apispublicgallerypublisherunityextensionunity-debuglatestassetbynameMicrosoft.VisualStudio.Services.VSIXPackage";
Path to VSCode executable
Value not set, set to "" or current path is invalid, try to autodetect it
If autodetect fails, a error will be printed and the default value set
If its not installed or the install folder isn't a "normal" one,
AutodetectCodePath will print a error message to the Unity Console
Get Program Files Path
The platforms "Program Files" path.
Should debug information be displayed in the Unity terminal?
Is the Visual Studio Code Integration Enabled?
We do not want to automatically turn it on, for in larger projects not everyone is using VSCode
When turning the plugin on, we should remove all the previous project files
Set value
Do not write the launch JSON file because the debugger uses its own
Update launch file
When opening a project in Unity, should it automatically open in VS Code.
Should the launch.json file be written?
Useful to disable if someone has their own custom one rigged up
Should the plugin automatically update itself.
When was the last time that the plugin was updated?
Feature creation date.
Quick reference to the VSCode launch settings file
The full path to the project
Should the script editor be reverted when quiting Unity.
Useful for environments where you do not use VSCode for everything.
Quick reference to the VSCode settings folder
Integration Constructor
Add Update Check
Open VS Code automatically when project is loaded
Event for when script is reloaded
Force Unity To Write Project File
Reflection!
Update the solution files so that they work with VS Code
No need to process if we are not enabled
Try to find automatically the installation of VSCode
return possiblePaths[0]; returns the default one, printing a warning message 'executable not found'
Call VSCode with arguments
Check the path to see if there is "Insiders"
Check for Updates with GitHub
Because were not a runtime framework, lets just use the simplest way of doing this
fileContent = webClient.DownloadString("https:raw.githubusercontent.comdotBunnyVSCodemasterPluginsEditorVSCode.cs");
Don't go any further if there is an error
Set the last update time
Fix for oddity in downlo
Jump over junk characters
Always make sure the file is writable
Write update file
Force update on text file
Checks whether it should auto-open VSCode
VSCode() gets called on Launch and Run, through IntializeOnLoad
https:docs.unity3d.comScriptReferenceInitializeOnLoadAttribute.html
To make sure it only opens VSCode when Unity (re)launches (i.e. opens a project),
we compare the launch time, which we calculate using EditorApplication.timeSinceStartup.
If launch time has changed, then Unity was re-opened
Launch VSCode
Save new launch time
Clear out any existing project files and lingering stuff that might cause problems
Replace with our clean files (only in Unity 5)
Force Unity Preferences Window To Read From Settings
I want that window, please and thank you
Only run this when the editor window is visible (cause its what screwed us up)
Determine what port Unity is listening for on Windows
Not thread safe (yet!)
Manually install the original Unity Debuger
This should auto update to the latest.
Don't go any further if there is an error
Do we have a file to install?
HACK: This is in until Unity can figure out why MD keeps opening even though a different program is selected.
Force the project files to be sync
Load Project
Print a error message to the Unity Console about not finding the code executable
VS Code Integration Preferences Item
Contains all 3 toggles: EnableDisable; Debug OnOff; Writing Launch File OnOff
Need the VS Code executable
TODO: Force Unity To Reload Preferences
This seems to be a hick up issue
Asset Open Callback (from Unity)
Called when Unity is about to open an asset.
bail out if we are not using VSCode
current path without the asset folder
determine asset that has been double clicked in the project view
additional file extensions
open supported object types
call 'open'
Didnt find a code file? let Unity figure it out
Executed when the Editor's playmode changes allowing for capture of required data
Detect when scripts are reloaded and relink playmode detection
Remove extraerroneous lines from a file.
Check Empty
Remove extraerroneous data from project file (content).
Moved to 3.5, 2.0 is legacy.
string targetPath = ""; "Temp" + Path.DirectorySeparatorChar + "bin" + Path.DirectorySeparatorChar + "Debug" + Path.DirectorySeparatorChar + ""; OutputPath
Remove extraerroneous data from solution file (content).
Replace Solution Version
Remove Solution Properties (Unity Junk)
Update Visual Studio Code Launch file
Write out proper formatted JSON (hence no more SimpleJSON here)
Write out proper formatted JSON (hence no more SimpleJSON here)
Update Unity Editor Preferences
Should we turn on this party!
App
Arguments
MonoDevelop Solution
Support Unity Proj (JS)
Restore previous app
Restore previous args
Restore MD setting
Restore MD setting
Always leave editor attaching on, I know, it solves the problem of needing to restart for this
to actually work
Determines if the current path to the code executable is valid or not (exists)
Write Default Workspace Settings
Associations
Hidden Files
Project Files
Media Files
Video
Audio
Textures
Models
Unity File Types
Folders
Dont like the replace but it fixes the issue with the JSON
VSCode Asset AssetPostprocessor
This will ensure any time that the project files are generated the VSCode versions will be made
Undocumented Event
On documented, project generation event callback
Force execution of VSCode update